package com.hhc.netty;

import android.util.Log;


import com.alibaba.fastjson.JSONObject;
import com.example.administrator.smartdevice.event.AskListEvent;
import com.example.administrator.smartdevice.event.MessageEvent;
import com.example.administrator.smartdevice.event.UpdateEvent;
import com.example.administrator.smartdevice.net.HttpUtils;
import com.example.administrator.smartdevice.net.RequestCallback;
import com.example.administrator.smartdevice.utils.AgentSharedPreferences;
import com.example.administrator.smartdevice.utils.AppApplication;
import com.example.administrator.smartdevice.utils.ServerConstants;

import org.greenrobot.eventbus.EventBus;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * Created by huhaichao on 2018/4/9.
 */

public class NettyClient implements RequestCallback {
    public static final int DISCONNECTION = 0;//断开连接
    public static final int CONNECTING = 1;//正在连接
    public static final int CONNECTED = 2;//连接成功
    private static final String TAG = "hhc";
    public static NettyClient nettyClient = null;
    private int connectState = DISCONNECTION;//连接状态
    private SocketChannel socketChannel = null;
    private EventLoopGroup workerGroup = null;
    private Bootstrap bootstrap = null;
    private List<DeviceModel> deviceList = new ArrayList<>();//存上线设备相关信息
    private List<MessageEvent> askList = new ArrayList<>();//存请求加入的设备相关信息
    private DeviceModel deviceModel;

    private ChannelFutureListener listener = new ChannelFutureListener() {
        @Override
        public void operationComplete(ChannelFuture future) throws Exception {
            if (future.isSuccess()) {
                Log.e(TAG, "operationComplete: 连接服务器成功");
                setConnectState(CONNECTED);
                socketChannel = (SocketChannel) future.channel();
            } else {
                Log.e(TAG, "operationComplete: 连接服务器失败");
                setConnectState(DISCONNECTION);
                future.channel().eventLoop().schedule(new Runnable() {
                    @Override
                    public void run() {
                        doConnect();
                    }
                }, 3L, TimeUnit.SECONDS);
            }
        }
    };

    private NettyClient() {
        init();
    }

    public static NettyClient getInstance() {
        if (nettyClient == null) {
            nettyClient = new NettyClient();
        }
        return nettyClient;
    }

    private void init() {
//        MessageEvent messageEvent1 = new MessageEvent();
//        messageEvent1.setOperationType("10");
//        messageEvent1.setApplianceId("123451");
//        messageEvent1.setApplianceType("001");
//        messageEvent1.setParams("123451");
//        askList.add(messageEvent1);
//
//        MessageEvent messageEvent2 = new MessageEvent();
//        messageEvent2.setOperationType("10");
//        messageEvent2.setApplianceId("123452");
//        messageEvent2.setApplianceType("002");
//        messageEvent2.setParams("123452");
//        askList.add(messageEvent2);
//
//        MessageEvent messageEvent3 = new MessageEvent();
//        messageEvent3.setOperationType("10");
//        messageEvent3.setApplianceId("123453");
//        messageEvent3.setApplianceType("003");
//        messageEvent3.setParams("123453");
//        askList.add(messageEvent3);
//
//        MessageEvent messageEvent4 = new MessageEvent();
//        messageEvent4.setOperationType("10");
//        messageEvent4.setApplianceId("123454");
//        messageEvent4.setApplianceType("004");
//        messageEvent4.setParams("123454");
//        askList.add(messageEvent4);
//
//        MessageEvent messageEvent5 = new MessageEvent();
//        messageEvent5.setOperationType("10");
//        messageEvent5.setApplianceId("123455");
//        messageEvent5.setApplianceType("005");
//        messageEvent5.setParams("123455");
//        askList.add(messageEvent5);

        workerGroup = new NioEventLoopGroup();
        bootstrap = new Bootstrap(); // (1)
        bootstrap.group(workerGroup); // (2)
        bootstrap.channel(NioSocketChannel.class); // (3)
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true); // (4)
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel channel) throws Exception {
                channel.pipeline().addLast(new IdleStateHandler(0, 5, 0, TimeUnit.SECONDS));//在出现超时事件时会被触发，包括读空闲超时或者写空闲超时
                channel.pipeline().addLast(new ObjectEncoder());//object对象传递
                channel.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
                channel.pipeline().addLast(new NettyClientHandler());
            }
        });
    }

    public void doConnect() {
        if (getConnectState() != CONNECTED) {
            try {
                Log.e(TAG, "doConnect: 正在连接...");
                setConnectState(CONNECTING);
                ChannelFuture f = bootstrap.connect(ServerConstants.NETTY_IP, ServerConstants.NETTY_PORT).sync();
                f.addListener(listener);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //断开连接
    public void disconnect() {
        if (socketChannel != null) {
            socketChannel.closeFuture();
            socketChannel.close();
            socketChannel = null;
        }
        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
            workerGroup = null;
        }
        if (bootstrap != null) {
            bootstrap = null;
        }
        if (nettyClient != null) {
            nettyClient = null;
        }
        setConnectState(DISCONNECTION);
    }

    public int getConnectState() {
        return connectState;
    }

    public void setConnectState(int connectState) {
        this.connectState = connectState;
    }

    public void sendMessage(NettyBaseMsg nettyBaseMsg) {
        if (NettyClient.getInstance().getConnectState() != NettyClient.CONNECTED) {
            doConnect();
        } else {
            socketChannel.writeAndFlush(nettyBaseMsg);
        }
    }

    public List<DeviceModel> getDeviceList() {
        return deviceList;
    }

    public List<MessageEvent> getAskList() {
        return askList;
    }

    public void addDevice(MessageEvent messageEvent) {
        boolean exist = false;
        for (int i = 0; i < askList.size(); i++) {
            if (askList.get(i).getApplianceId().equals(messageEvent.getApplianceId())) {
                exist = true;
                break;
            }
        }
        if (!exist) {
            askList.add(messageEvent);
        }
    }

    //家电上线状态
    public void deviceOnline(DeviceModel deviceModel) {
        //同时更新申请了该家电的用户(同时还要在线)
        boolean exist = false;
        for (int i = 0; i < deviceList.size(); i++) {
            if (deviceList.get(i).getApplianceId().equals(deviceModel.getApplianceId())) {
                exist = true;
                break;
            }
        }
        if (!exist) {
            deviceList.add(deviceModel);
            EventBus.getDefault().post(new UpdateEvent());
            //同时更新添加了该家电的用户(同时还要在线)
            updateToOwn(deviceModel.getApplianceId(), deviceModel.getOnlineStatus(), deviceModel.getStatus());
            getMemberList(1001, deviceModel.getApplianceId());
        }
    }

    //家电下线状态
    public void deviceOffline(DeviceModel deviceModel) {
        for (int i = 0; i < deviceList.size(); i++) {
            String applianceId = deviceModel.getApplianceId();
            String record = deviceList.get(i).getApplianceId();
            if (applianceId.equals(record)) {
                getMemberList(1002, applianceId);
                updateToOwn(deviceModel.getApplianceId(), deviceModel.getOnlineStatus(), deviceModel.getStatus());
                getDeviceList().remove(i);
            }
        }
    }

    public List<DeviceModel> getDeviceStatus(List<DeviceModel> askList) {
        for (int i = 0; i < askList.size(); i++) {
            Log.d(TAG, "请求的设备deviceId=" + askList.get(i).getDeviceId());
            Log.d(TAG, "请求的设备applianceId=" + askList.get(i).getApplianceId());
            for (int j = 0; j < deviceList.size(); j++) {
                Log.d(TAG, "在线设备deviceId=" + deviceList.get(j).getDeviceId());
                Log.d(TAG, "在线设备applianceId=" + deviceList.get(j).getApplianceId());
                if (askList.get(i).getDeviceId().equals(deviceList.get(j).getDeviceId()) &&
                        askList.get(i).getApplianceId().equals(deviceList.get(j).getApplianceId())) {
                    askList.get(i).setOnlineStatus(deviceList.get(j).getOnlineStatus());
                    askList.get(i).setStatus(deviceList.get(j).getStatus());
                }
            }
        }
        return askList;
    }

    //设备状态改变
    public void deviceStatusChange(DeviceModel deviceModel) {
        this.deviceModel = deviceModel;
        //先判断是否还在线上
        String applianceId = deviceModel.getApplianceId();
        for (int i = 0; i < getDeviceList().size(); i++) {
            String record = getDeviceList().get(i).getApplianceId();
            if (applianceId.equals(record)) {
                //保证是上线状态
                if (getDeviceList().get(i).getOnlineStatus().equals("10")) {
                    //本地保存的相应状态要改变
                    getDeviceList().get(i).setStatus(deviceModel.getStatus());
                    EventBus.getDefault().post(new UpdateEvent());
                    updateToOwn(deviceModel.getApplianceId(), deviceModel.getOnlineStatus(), deviceModel.getStatus());
                    //同时通知更新
                    getMemberList(1003, applianceId);
                }
            }
        }
    }

    public void updateApplianceOnline(DeviceModel[] list, String onlineStatus, String status) {
        for (int i = 0; i < list.length; i++) {
            DeviceModel deviceModel = new DeviceModel();
            //基本项：device_id和appliance_id
            deviceModel.setMemberId(list[i].getMemberId());
//            deviceModel.setDeviceId(list[i].getDeviceId());
            deviceModel.setApplianceId(list[i].getApplianceId());
            //家电上线状态(只有上线设备)
            deviceModel.setOnlineStatus(onlineStatus);
            //家电开关状态
            deviceModel.setStatus(status);
            //这里是返回单个家电状态
            List<DeviceModel> listOnly = new ArrayList<>();
            listOnly.add(deviceModel);
            ///向 相关的 移动端 发送 家电上线通知(REPLY_STATUS)
            NettyReplyStatusMsg nettyReplyStatusMsg = new NettyReplyStatusMsg();
            //1.家电上线应该向 添加了该家电 的移动端 发送 家电上线通知
            nettyReplyStatusMsg.setClientId(list[i].getMemberId());
//            nettyReplyStatusMsg.setDeviceId(list[i].getDeviceId());
            nettyReplyStatusMsg.setList(listOnly);
            NettyClient.getInstance().sendMessage(nettyReplyStatusMsg);
        }

    }

    @Override
    public void onFailureCallback(int requestCode, Object object) {

    }

    @Override
    public void onSuccessCallback(int requestCode, Object object) {
        if (object != null) {
            switch (requestCode) {
                case 1001:
                    Log.d(TAG, "onSuccessCallback: " + object);
                    DeviceModel[] deviceOnline = (DeviceModel[]) HttpUtils.getData(object, DeviceModel[].class);
                    if (deviceOnline != null) {
                        updateApplianceOnline(deviceOnline, "10", "20");
                    }
                    break;
                case 1002:
                    Log.d(TAG, "onSuccessCallback: " + object);
                    DeviceModel[] deviceOffline = (DeviceModel[]) HttpUtils.getData(object, DeviceModel[].class);
                    if (deviceOffline != null) {
                        updateApplianceOnline(deviceOffline, "20", "20");
                    }
                    break;
                case 1003:
                    Log.d(TAG, "onSuccessCallback: " + object);
                    DeviceModel[] deviceStatus = (DeviceModel[]) HttpUtils.getData(object, DeviceModel[].class);
                    if (deviceStatus != null) {
                        updateApplianceOnline(deviceStatus, "10", deviceModel.getStatus());
                    }
                    break;
            }
        }
    }

    //授权表
    public void getMemberList(int requestCode, String applianceId) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("memberId", AgentSharedPreferences.getMemberInfo(AppApplication.getContext()).getMemberTelephone());
        jsonObject.put("applianceId", applianceId);
        HttpUtils.post(AppApplication.getContext(), requestCode, ServerConstants.QUERY_AUTHORIZED_LIST, jsonObject.toString(), this);
    }

    public void updateToOwn(String applianceId, String onlineStatus, String status) {
        DeviceModel deviceModel = new DeviceModel();
        //基本项：device_id和appliance_id
        deviceModel.setMemberId(AgentSharedPreferences.getMemberInfo(AppApplication.getContext()).getMemberTelephone());
//            deviceModel.setDeviceId(list[i].getDeviceId());
        deviceModel.setApplianceId(applianceId);
        //家电上线状态(只有上线设备)
        deviceModel.setOnlineStatus(onlineStatus);
        //家电开关状态
        deviceModel.setStatus(status);
        //这里是返回单个家电状态
        List<DeviceModel> listOnly = new ArrayList<>();
        listOnly.add(deviceModel);
        ///向 相关的 移动端 发送 家电上线通知(REPLY_STATUS)
        NettyReplyStatusMsg nettyReplyStatusMsg = new NettyReplyStatusMsg();
        //1.家电上线应该向 添加了该家电 的移动端 发送 家电上线通知
        nettyReplyStatusMsg.setClientId(AgentSharedPreferences.getMemberInfo(AppApplication.getContext()).getMemberTelephone());
        nettyReplyStatusMsg.setList(listOnly);
        NettyClient.getInstance().sendMessage(nettyReplyStatusMsg);
    }
}
